﻿using Servo_Tool.entity;
using Servo_Tool.utils;
using Servo_Tool.cache;
using Servo_Tool.client;
using Servo_Tool.dal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Servo_Tool.service;
using Servo_Tool.domain;

namespace Servo_Tool.handler
{
    public class ListenHandler
    {
        private readonly string unitNo;
        private IClientNet client;
        public event Action<string, string, string> ShowMessageUpdated;
        private FuncServiceImpl funcService = new FuncServiceImpl();
        //事件判定
        private readonly JudgeHandler judgeHandler;
        //内容写入
        private readonly WriteHandler writeHandler;
        public ListenHandler(string unitNo, JudgeHandler judgeHandler, WriteHandler writeHandler)
        {
            this.unitNo = unitNo;
            this.judgeHandler = judgeHandler;
            this.writeHandler = writeHandler;
        }

        public void StartListening()
        {
            //获取需要监听的PLC_READ信息
            if (GlobalCachePool.plcReads_dict.TryGetValue(unitNo, out List<PlcReadEntity> reads))
            {
                //获取相关设备
                if (GlobalCachePool.client_dict.TryGetValue(unitNo, out client))
                {
                    //开始监听(正式为循环监听,测试为单次监听)
                    foreach (PlcReadEntity read in reads)
                    {
                        ShowMessage("0", $"设备{unitNo}所属监听{read.READ_NO}开启!起始标签[{read.START_ITEM}]长度[{read.READ_LEN}]");
                        ThreadPool.QueueUserWorkItem(obj =>
                        {
                            while (true)
                            {
                                ListenProcess(read.READ_NO);
                                //轮询监听间隔时间(可通过配置[PLC_READ]中的READ_INTERVAL调整)
                                Thread.Sleep(3000);
                            }
                        });
                    }
                }
                else
                {
                    ShowMessage("500", $"设备{unitNo}未连接!");
                }
            }
        }

        public void ListenProcess(string readNo)
        {
            //0.设备连接建立完成再监听
            if (!client.HasStarted())
            {
                return;
            }
            bool isEquals = false;
            //1.获取READ的详细信息
            if (!GlobalCachePool.single_plcRead_dict.TryGetValue(readNo, out PlcReadEntity read))
            {
                return;
            }
            try
            {
                //ShowMessage("0", $"监听信息,BLOCK[{read.DB_BLOCK}]起始标签[{read.START_ITEM}]长度[{read.READ_LEN}]");
                short[] newByte = client.ReadData(read.DB_BLOCK, read.START_ITEM, read.READ_LEN);
                if (newByte == null)
                {
                    ShowMessage("500", $"数据读取失败,请检查PLC连接!");
                    return;
                }
                //3.处理信息(获取该READ缓存的ushort[]数据,做是否一致的判断)
                if (GlobalCachePool.read_data_dict.TryGetValue(readNo, out short[] oldByte))
                {
                    //判断newByte是否与oldByte数据一致
                    if (oldByte != null)
                    {
                        isEquals = newByte.SequenceEqual(oldByte);
                    }
                }
                else
                {
                    //如果缓存中没有记录该read的short[],则先赋初始值null
                    GlobalCachePool.read_data_dict.Add(readNo, null);
                }
                //如果数据不一致则进行数据更新
                if (!isEquals)
                {
                    //ShowMessage("0", $"[{readNo}]在内存中的ushort数组数据发生变化!");
                    GlobalCachePool.read_data_dict[readNo] = newByte;
                    //获取该PLC_READ所属的PLC_ITEM进行遍历,确认哪些点的值发生了变化
                    if (!GlobalCachePool.plcItems_dict.TryGetValue(readNo, out List<PlcItemEntity> items))
                    {
                        return;
                    }
                    //将变更的PLC_ITEM记录下来
                    List<PlcItemEntity> changedItems = new List<PlcItemEntity>();
                    foreach (PlcItemEntity item in items)
                    {
                        //获取该item读取到的值
                        string value = OmronHexUtils.GetString(newByte, item.ITEM_ADR, item.DATA_LEN, item.DISPLAY_TYPE);
                        //获取该信号点的旧值
                        if (!GlobalCachePool.single_plcItem_dict.TryGetValue(item.ITEM_NO, out PlcItemEntity oldItem))
                        {
                            continue;
                        }
                        //判断该item的值是否发生变化
                        if (value.Equals(oldItem.ITEM_VALUE))
                        {
                            continue;
                        }

                        //记录变更值的信号点
                        ShowMessage("0", $"[{item.ITEM_NAME}]的值发生变化,旧值[{oldItem.ITEM_VALUE}],新值[{value}]");

                        //值变化则记录
                        item.OLD_VALUE = oldItem.ITEM_VALUE;
                        item.ITEM_VALUE = value;
                        item.UPDATE_DATE = DateTime.Now;

                        GlobalCachePool.single_plcItem_dict[item.ITEM_NO] = item;
                        changedItems.Add(item);
                    }
                    //更新数据库
                    DBFactory.BatchUpdateOfItem(changedItems);
                }
                //无论信号点的值是否变化,都需要判定该PLC_READ是否包含绑定事件的信号点,如果有则触发
                //judgeHandler.JudgeEventByRead(readNo);
            }
            catch (Exception e)
            {
                ShowMessage("500", $"[{readNo}]监听异常!causeBy:{e.Message}");
            }
        }

        public void ShowMessage(string code, string msg)
        {
            ShowMessageUpdated?.Invoke(unitNo, code, msg);
        }
    }
}
